package com.xkh.common.controller;

import cn.hutool.core.util.RandomUtil;
import com.xkh.common.common.constant.GuardThread;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

/**
 * @author xkh
 * 2020/10/5
 */
@RestController
@RequestMapping("util/order")
@Api(tags = "订单模块")
@Slf4j
public class OrderController {
    /**
     * 商品总库存
     */
    private static int stock = 10;
    /**
     * 自定义锁的超时时间
     */
    private int timeOut = 4 * 1000;
    /**
     * 自定义商品key
     */
    private static String distributedKey = "discounts_lock";
    /**
     * 定义重新执行次数
     */
    private static int robNo = 5;

    @Autowired
    public StringRedisTemplate stringRedisTemplate;


    @ApiOperation("redis分布式锁模拟抢单")
    @GetMapping("/goods")
    public String goods() {
        String randomNumbers = RandomUtil.randomNumbers(6);
        Boolean lockResult = stringRedisTemplate.opsForValue().setIfAbsent(distributedKey, randomNumbers, timeOut, TimeUnit.SECONDS);
        if (!lockResult) {
            return "当前活动参与人数过多，请稍后重试！";
        }
        //自定义一个线程当做当前线程的守护线程，用来给当前线程没执行完，给锁加失效时间(如果当前设置锁超时时间为10秒，这个线程就是用来给锁加时间，因为业务还没执行完，不能释放锁，只有当执行完或者挂掉，确保释放锁)
        GuardThread guardThread = new GuardThread(distributedKey, timeOut, stringRedisTemplate);
        //如果当前线程处理业务因为某些原因挂了，那么守护线程也跟着挂
        guardThread.setDaemon(true);
        guardThread.start();
        try {
            if (stock > 0) {
                Thread.sleep(1000);
                stock--;
                log.info("用户{}抢单成功跳出...所剩库存：{}", randomNumbers, stock);
            } else {
                log.info("暂无库存");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //确保锁是由当前线程释放的，再释放锁
            if (stringRedisTemplate.opsForValue().get(distributedKey).equals(randomNumbers)) {
                stringRedisTemplate.delete(distributedKey);
            }
        }
        return "所剩库存:" + stock;
    }

}
